import camelcaseKeys from 'camelcase-keys'
import {auth} from './proto_gen/auth/auth_pb'
import {wxLogin} from '../utils/wx.api'

export namespace RentalCar {

    const serverAddr = 'http://localhost:8080'

    const AUTH_ERR = 'AUTH_ERR'

    const authData = {
        token: '',
        expireMs: 0
    }

    export interface RequestOption<REQ, RES> {
        method: 'GET' | 'POST' | 'PUT' | 'DELETE'
        path: string,
        data?: REQ,
        respMarshaller: (r: object) => RES
    }

    export interface AuthOption {
        attachAuthHeader: boolean
        retryOnAuthError: boolean
    }

    // 发送请求
    function sendRequest<REQ, RES>(o: RequestOption<REQ, RES>, a: AuthOption): Promise<RES> {

        return new Promise((resolve, reject) => {

            const header: Record<string, any> = {}

            if (a.attachAuthHeader) {

                // token没有过期
                if (authData.token && authData.expireMs >= Date.now()) {

                    header.authorization = 'Bearer ' + authData.token

                } else {

                    // 报错
                    reject(AUTH_ERR)
                    return

                }

            }

            wx.request({
                    url: serverAddr + o.path,
                    method: o.method,
                    data: o.data!,
                    header,
                    success: res => {
                        // 未认证
                        if (res.statusCode === 401) {
                            reject(AUTH_ERR)
                        } else if (res.statusCode >= 400) {
                            reject(res)
                        } else {
                            resolve(o.respMarshaller(camelcaseKeys(res.data as object, {deep: true})))
                        }

                    },
                    fail: reject
                }
            )

        })
    }


    // 登录
    export async function login() {

        // 请求时间
        const reqTimeMS = Date.now()

        // token有效
        if (authData.token && authData.expireMs >= reqTimeMS) return

        const wxLoginResp = await wxLogin()

        const loginResp = await sendRequest<auth.v1.ILoginRequest, auth.v1.ILoginResponse>({
            method: 'POST',
            path: '/v1/auth/login',
            data: {
                code: wxLoginResp.code
            },
            respMarshaller: auth.v1.LoginResponse.fromObject
        }, {
            attachAuthHeader: false,
            retryOnAuthError: false,
        })


        // 一定有值
        authData.token = loginResp.accessToken!
        authData.expireMs = reqTimeMS + loginResp.expireIn! * 1000

    }

    // 登录流程管理
    export async function sendRequestWithAuthRetry<REQ, RES>(o: RequestOption<REQ, RES>, a?: AuthOption): Promise<RES> {

        const authOpt = a || {
            attachAuthHeader: true,
            retryOnAuthError: true
        }

        try {
            // 先登录
            await login()

            return sendRequest(o, authOpt)

        } catch (err) {

            if (err === AUTH_ERR && authOpt.retryOnAuthError) {

                authData.token = ''
                authData.expireMs = 0

                return sendRequestWithAuthRetry(o, {
                    attachAuthHeader: authOpt.attachAuthHeader,
                    retryOnAuthError: false
                })

            } else {
                throw err
            }

        }


    }


}